﻿// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Copyright (c) 2011, Dr. Masroor Ehsan
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the author nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// $Author:$
// $Id:$
// $Rev:$
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using FileHelpers;
using MaxTrader.IntradayQuotes.Core;
using MaxTrader.IntradayQuotes.MapReduce;
using Rhino.Etl.Core;
using Rhino.Etl.Core.Files;

namespace mrtest
{
    [DelimitedRecord(",")]
    public class EtlStockQuote
    {
        public string Symbol { get; set; }

        public string Date { get; set; }

        public string Time { get; set; }

        public decimal Ltp { get; set; }

        public decimal High { get; set; }

        public decimal Low { get; set; }

        public decimal Close { get; set; }

        public decimal PrevClose { get; set; }

        public decimal Change { get; set; }

        public int Trades { get; set; }

        public int Volume { get; set; }
    }

    internal class Program
    {
        private static EtlStockQuote RowToEtlQuote(QuackingDictionary row)
        {
            var quote = new EtlStockQuote
                            {
                                Symbol = (string) row["Symbol"],
                                Ltp = (decimal) row["Ltp"],
                                High = (decimal) row["High"],
                                Low = (decimal) row["Low"],
                                Close = (decimal) row["Close"],
                                PrevClose = (decimal) row["PrevClose"],
                                Change = (decimal) row["Change"],
                                Trades = (int) row["Trades"],
                                Volume = (int) row["Volume"]
                            };
            return quote;
        }

        private static DateTime TimeFromFileName(string fname)
        {
            var parts = fname.Split(new[] {'^'});
            parts = parts[1].Split(new[] {'.'});
            var dt = DateTime.ParseExact(parts[0], "HHmm", CultureInfo.InvariantCulture);
            return dt;
        }

        private static CompositeIntradayStockSnapshots FromFile(string csv)
        {
            var time = TimeFromFileName(csv);

            var file = FluentFile.For<EtlStockQuote>().From(csv);
            var list = new List<EtlStockQuote>();

            foreach (var obj in file)
            {
                list.Add(RowToEtlQuote(Row.FromObject(obj)));
            }

            var market = new CompositeIntradayStockSnapshots(StockExchange.Dse);
            foreach (var q in list)
            {
                market.Add(q.Symbol, time, q.Ltp, q.High, q.Low, q.Volume);
            }
            return market;
        }

        private static AggregateStockSnapshot Reduce(AggregateStockSnapshot left, AggregateStockSnapshot right)
        {
            var map = new IntradayQuotesProcessorMapReduce {Left = left, Right = right};
            map.Initialize();
            map.Execute();
            return map.Output;
        }

        private static void Process(string csvDir)
        {
            var files = Directory.GetFiles(csvDir);

            var left = FromFile(files[0]);

            foreach (var file in files.Skip(1))
            {
                var right = FromFile(file);
                var reduced = Reduce(left.LastQuotesForAllStocks(), right.LastQuotesForAllStocks());
                foreach (var quote in reduced.Values)
                {
                    left.Add(quote.Symbol, quote.UtcTimeStamp, quote.Price, quote.High, quote.Low,
                             quote.CumulativeVolume, quote.VolumeDifference);
                }
            }

            foreach (var symbol in left.Symbols())
            {
                GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period1Min);
                GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period5Min);
                GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period10Min);
                GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period15Min);
                GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period30Min);
                GenerateTimeSeries(csvDir, symbol, left, Timeframe.PeriodHour);
                //GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period2Hour);
                //GenerateTimeSeries(csvDir, symbol, left, Timeframe.Period4Hour);
            }

            using (var f = new StreamWriter(csvDir + "_quotes.csv"))
            {
                f.Write(left.DumpAll());
            }
        }

        private static void GenerateTimeSeries(string csvDir, string symbol, CompositeIntradayStockSnapshots market,
                                               Timeframe period)
        {
            var snap = market.Snapshot(symbol);
            if (snap != null)
            {
                var quotes = snap.GetQuotes();
                var period5 = new TimeSeriesStockSnapshots(symbol,
                                                           StockExchange.Dse,
                                                           quotes.First().UtcTimeStamp,
                                                           quotes.Last().UtcTimeStamp,
                                                           period);
                period5.AddQuotes(snap);
                using (var f = new StreamWriter(@"export\__" + csvDir + "_" + symbol + "_" + (int) period + ".csv"))
                {
                    f.Write(period5.DumpAll());
                }
            }
        }

        private static void Main(string[] args)
        {
            for (int i = 5; i < 10; i++)
            {
                Process(i.ToString());
            }
        }
    }
}